package com.zlyx.easy.core.utils;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import com.zlyx.easy.core.map.Maps;
import com.zlyx.easy.core.map.ObjectMap;
import com.zlyx.easy.core.tool.EasyBuffer;

/**
 * @Auth 赵光
 * @Describle
 * @2019年1月11日 下午5:01:22
 */
public final class MethodUtils {

	public static Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
		final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
				.getDeclaredConstructor(Class.class, int.class);
		if (!constructor.isAccessible()) {
			constructor.setAccessible(true);
		}
		final Class<?> declaringClass = method.getDeclaringClass();
		return constructor
				.newInstance(declaringClass,
						MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED | MethodHandles.Lookup.PACKAGE
								| MethodHandles.Lookup.PUBLIC)
				.unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
	}

	public static boolean isDefaultMethod(Method method) {
		return (method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
				&& method.getDeclaringClass().isInterface();
	}

	public static Type getReturnType(Method method) {
		Type type = method.getGenericReturnType();
		if (type instanceof ParameterizedType) {
			Type[] types = ((ParameterizedType) type).getActualTypeArguments();
			if (types.length > 0) {
				return types[0];
			}
		}
		return null;
	}

	/**
	 * 从spring框架中获得参数名称(ASM机制)
	 * 
	 * @param method
	 * @return
	 */
	public static String[] getParameterNames(Method method) {
		return NameDiscover.getParameterNames(method);
	}

	/**
	 * 获取方法的参数名称和参数map
	 * 
	 * @param method
	 * @return
	 */
	public static Map<String, Parameter> getParamterMap(Method method) {
		Map<String, Parameter> parameterMap = Maps.newMap();
		String[] names = getParameterNames(method);
		Parameter[] paramaters = method.getParameters();
		for (int i = 0; i < paramaters.length; i++) {
			parameterMap.put(names[i], paramaters[i]);
		}
		return parameterMap;
	}

	/**
	 * 将某个方法的参数数组转换为参数名和参数值的Map形式
	 * 
	 * @param method
	 * @param args
	 * @return
	 */
	@SuppressWarnings({ "unchecked" })
	public static ObjectMap getParamsMap(Method method, Object[] args) {
		ObjectMap paramsMap = ObjectMap.newMap();
		if (args != null) {
			Parameter[] paramters = method.getParameters();
			Map<String, Object> paramMap = null;
			Map<String, String[]> parameterMap = null;
			for (int i = 0; i < paramters.length; i++) {
				if (args[i] != null && !(ServletRequest.class.isAssignableFrom(paramters[i].getType())
						|| ServletResponse.class.isAssignableFrom(paramters[i].getType()))) {
					if (Map.class.isAssignableFrom(paramters[i].getType())) {
						paramMap = (Map<String, Object>) args[i];
						if (paramMap != null) {
							paramsMap.putAll(paramMap);
						}
					} else if (HttpServletRequest.class.isAssignableFrom(paramters[i].getType())) {
						parameterMap = ((HttpServletRequest) args[i]).getParameterMap();
						if (parameterMap != null) {
							paramsMap.putAll(parameterMap);
						}
					} else {
						paramsMap.put(paramters[i].getName(), args[i]);
					}
				}
			}
		}
		return paramsMap;
	}

	/**
	 * 获取被代理方法的真实方法对象
	 * 
	 * @param tClass
	 * @param method
	 * @return
	 */
	public static Method getRealMethod(Class<?> tClass, Method method) {
		try {
			method = tClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
		} catch (Exception e) {
			Class<?> sClass = tClass.getSuperclass();
			if (sClass != Object.class) {
				method = getRealMethod(sClass, method);
			}
		}
		return method;
	}

	/**
	 * 获取被重写的父类方法
	 * 
	 * @param tClass
	 * @param name
	 * @return
	 */
	public static Method getOverrideMethod(Class<?> tClass, String name) {
		Method method = null;
		try {
			method = tClass.getDeclaredMethod(name);
		} catch (Exception e) {
			Class<?> sClass = tClass.getSuperclass();
			if (sClass != Object.class) {
				method = getOverrideMethod(sClass, name);
			}
		}
		return method;
	}

	/**
	 * 获取有帮助的方法名(类路径.方法名称)
	 * 
	 * @param method
	 * @return
	 */
	public static String getHelpfulName(Method method) {
		return EasyBuffer.newString(method.getDeclaringClass().getName(), ".", method.getName());
	}

}
